﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml.Linq;

namespace SweetWeather.View
{
    /// <summary>
    /// CalendarPage.xaml 的交互逻辑
    /// </summary>
    public partial class CalendarPage : Page
    {
        private ICalendar mainCalendar;
        private ICalendar subsidiaryCalendar;

        // Specified year, month and day
        private int year;
        private int month;
        private int day;

        private CultureInfo localCultureInfo = new CultureInfo(CultureInfo.CurrentUICulture.ToString());
        private UniformGrid calendarDisplayUniformGrid;

        private string[] WeekDays = new string[]{ 
            SweetWeather.Properties.Resources.Sunday,
            SweetWeather.Properties.Resources.Monday,
            SweetWeather.Properties.Resources.Tuesday, 
            SweetWeather.Properties.Resources.Wednesday,
            SweetWeather.Properties.Resources.Thursday, 
            SweetWeather.Properties.Resources.Friday,
            SweetWeather.Properties.Resources.Saturday 
        };



        public CalendarPage()
        {
            InitializeComponent();

            this.Loaded += WindowOnLoad;
            //this.MouseLeftButtonDown += WindowOnMove;
            year = DateTime.Now.Year;
            month = DateTime.Now.Month;
            day = DateTime.Now.Day;

            mainCalendar = new StandardGregorianCalendar();

            //Detect whether the application is running in a zh-CN locale
            subsidiaryCalendar = localCultureInfo.ToString() == "zh-CN" ? new ChineseSweetWeather() : null;

            WeekdayLabelsConfigure();
            TimeSwitchButtonsConfigure();
        }


        public void DisplayCalendar(int year, int month)
        {
            int dayNum = DateTime.DaysInMonth(year, month);
            calendarDisplayUniformGrid = GetCalendarUniformGrid(CalendarListBox);

            DateTime dateTime = new DateTime(year, month, 1);
            calendarDisplayUniformGrid.FirstColumn = (int)(dateTime.DayOfWeek);
            List<DateEntry> mainDateList = mainCalendar.GetDaysOfMonth(year, month);
            List<DateEntry> subsidiaryDateList = null;
            if (subsidiaryCalendar != null)
            {
                subsidiaryDateList = subsidiaryCalendar.GetDaysOfMonth(year, month);
            }

            for (int i = 0; i < dayNum; i++)
            {
                Label mainDateLabel = new Label();
                mainDateLabel.HorizontalAlignment = HorizontalAlignment.Center;
                mainDateLabel.VerticalAlignment = VerticalAlignment.Center;
                mainDateLabel.Background = Brushes.Transparent;
                mainDateLabel.Padding = new Thickness(0, 0, 0, 0);
                mainDateLabel.Margin = new Thickness(0, 0, 0, 0);

                //This label is used to hold the holiday string.
                Label hiddenLabel = new Label();
                hiddenLabel.HorizontalAlignment = HorizontalAlignment.Stretch;
                hiddenLabel.VerticalAlignment = VerticalAlignment.Stretch;
                hiddenLabel.Visibility = Visibility.Collapsed;

                //If the application is not running in zh-CN env, 
                //it can display the date number bigger.
                mainDateLabel.FontSize = 20;

                //Weekend should be dispaly in red color.
                if (IsWeekEndOrFestival(ref dateTime, mainDateList, i))
                {
                    if (mainDateList[i].IsFestival)
                    {
                        hiddenLabel.Content = mainDateList[i].Text;
                    }
                }
                else
                {
                    hiddenLabel.Content = "";
                }
                mainDateLabel.Foreground = Brushes.White;

                mainDateLabel.Content = mainDateList[i].DateOfMonth.ToString(NumberFormatInfo.CurrentInfo);

                //If the application is running in a non zh-CN locale, display no lunar calendar.
                Label subsidiaryDateLabel = null;
                if (subsidiaryDateList != null)
                {
                    subsidiaryDateLabel = new Label();
                    subsidiaryDateLabel.HorizontalAlignment = HorizontalAlignment.Center;
                    subsidiaryDateLabel.VerticalAlignment = VerticalAlignment.Center;
                    subsidiaryDateLabel.Background = Brushes.Transparent;
                    subsidiaryDateLabel.Padding = new Thickness(0, 0, 0, 0);
                    subsidiaryDateLabel.Margin = new Thickness(0, 0, 0, 0);
                    subsidiaryDateLabel.FontSize = 13;

                    //Control the festival date to be red.
                    subsidiaryDateLabel.Foreground = Brushes.White;
                    subsidiaryDateLabel.Content = subsidiaryDateList[i].Text;
                }

                //Compose the final displaying unit.
                StackPanel stackPanel = new StackPanel();
                stackPanel.HorizontalAlignment = HorizontalAlignment.Stretch;
                stackPanel.VerticalAlignment = VerticalAlignment.Stretch;

                //天气情况
                Label lblWeather = new Label();
                lblWeather.Foreground = Brushes.White;
                lblWeather.FontWeight = FontWeight.FromOpenTypeWeight(1);
                lblWeather.HorizontalAlignment = HorizontalAlignment.Center;
                lblWeather.VerticalAlignment = VerticalAlignment.Bottom;
                lblWeather.Background = Brushes.Transparent;
                lblWeather.Margin = new Thickness(0, 0, 0, 2);
                lblWeather.FontSize = 12;
                try
                {
                    XElement element = XElement.Load(System.AppDomain.CurrentDomain.BaseDirectory + "Data\\Calendar.xml");
                    var result = (from pro in element.Elements("Day")
                                  where pro.Attribute("Name").Value.StartsWith(dateTime.ToString("yyyy-MM-dd"))
                                  select pro).FirstOrDefault();
                    if (result != null)
                        lblWeather.Content = result.Value;
                    else
                        lblWeather.Content = "暂无数据";
                }
                catch
                {
                }


                stackPanel.Children.Add(hiddenLabel);
                stackPanel.Children.Add(mainDateLabel);
                if (subsidiaryDateLabel != null)
                {
                    stackPanel.Children.Add(subsidiaryDateLabel);
                }
                stackPanel.Children.Add(lblWeather);
                CalendarListBox.Items.Add(stackPanel);
                dateTime = dateTime.AddDays(1);
            }
        }

        private static bool IsWeekEndOrFestival(ref DateTime dateTime, List<DateEntry> mainDateList, int i)
        {
            return ((int)dateTime.DayOfWeek == 6) || ((int)dateTime.DayOfWeek == 0) || mainDateList[i].IsFestival;
        }

        private void HighlightCurrentDate()
        {
            UIElementCollection dayCollection = calendarDisplayUniformGrid.Children;
            ListBoxItem today;
            int index = DateTime.Now.Day - 1;
            today = (ListBoxItem)(dayCollection[index]);
        }

        private UniformGrid GetCalendarUniformGrid(DependencyObject uniformGrid)
        {
            UniformGrid tempGrid = uniformGrid as UniformGrid;

            if (tempGrid != null)
            {
                return tempGrid;
            }

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(uniformGrid); i++)
            {
                DependencyObject gridReturn =
                    GetCalendarUniformGrid(VisualTreeHelper.GetChild(uniformGrid, i));
                if (gridReturn != null)
                {
                    return gridReturn as UniformGrid;
                }
            }
            return null;
        }

        //Configure the color of the weekday label.
        private void WeekdayLabelsConfigure()
        {
            UIElementCollection labelCollection = this.stackPanel1.Children;
            Label tempLabel;

            for (int i = 0; i < 7; i++)
            {
                tempLabel = (Label)labelCollection[i];
                tempLabel.Content = WeekDays[i];
            }
        }

        private void TimeSwitchButtonsConfigure()
        {
            PreviousMonthButton.Click += PreviousMonthOnClick;
            NextMonthButton.Click += NextMonthOnClick;
        }

        //Event handler
        private void WindowOnLoad(Object sender, EventArgs e)
        {
            DisplayCalendar(year, month);
            lblTime.Text = DateTime.Now.ToString("Y");
            HighlightCurrentDate();
        }

        private void UpdateMonth()
        {
            //Thread.Sleep(3000);
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()
            {
                CalendarListBox.BeginInit();
                CalendarListBox.Items.Clear();
                DisplayCalendar(year, month);
                CalendarListBox.EndInit();
                lblTime.Text = (new DateTime(year, month, 1)).ToString("Y", localCultureInfo);
                CalendarListBox.SelectedItem = null;

                //Check the calendar range and disable corresponding buttons
                CheckRange();
            });
        }

        private void PreviousMonthOnClick(Object sender, RoutedEventArgs e)
        {
            if (month == 1 && year == 1902)
            {
                return;
            }

            month -= 1;
            if (month == 0)
            {
                month = 12;
                year--;
            }
            Thread otherad = new Thread(UpdateMonth);
            otherad.Priority = ThreadPriority.Highest;
            otherad.Start();
        }

        private void NextMonthOnClick(Object sender, RoutedEventArgs e)
        {
            if (month == 12 && year == 2100)
            {
                return;
            }

            month += 1;
            if (month > 12)
            {
                month = 1;
                year++;
            }
            Thread otherad = new Thread(UpdateMonth);
            otherad.Priority = ThreadPriority.Highest;
            otherad.Start();
        }

        private void CheckRange()
        {
            PreviousMonthButton.IsEnabled = (month == 01 && year <= 1902) ? false : true;
            NextMonthButton.IsEnabled = (month == 12 && year >= 2100) ? false : true;
        }
    }
}
